#coding=utf-8
import datetime
import os
import time

import requests
from loguru import logger
from playwright.sync_api import sync_playwright
import traceback
import zipfile
import hashlib
import pandas as pd
import base64
import random
import json
import numpy
from dateutil.relativedelta import relativedelta


class PDD_BILL:
    def __init__(self, playwright, host, app_id):
        self.app_id = app_id
        self.secret = "P4I8HCOP1OP7432XZVKR2MPJKKVQ7J"
        self.playwright = playwright
        self.host = host
        self.context = None
        self.browser = None
        self.page = None
        self.index_url = "https://mms.pinduoduo.com/login/"
        self.fund_flow_download_path = os.path.join(os.getcwd(), 'pddFundFlow')
        self.tj_account = self.get_tujian_account()
        if not os.path.exists(self.fund_flow_download_path):
            os.makedirs(self.fund_flow_download_path)
        self.deposit_download_path = os.path.join(os.getcwd(), 'pddDeposit')
        if not os.path.exists(self.deposit_download_path):
            os.makedirs(self.deposit_download_path)

    def login(self, store):
        browser = self.playwright.firefox.launch(headless=False)
        self.context = browser.new_context(accept_downloads=True)
        self.page = self.context.new_page()
        self.page.goto(self.index_url, timeout=20000)
        self.wait(self.page)
        for t in range(10):
            try:
                if self.page.query_selector('button:has-text("已安装去使用")') is not None:
                    self.page.query_selector('button:has-text("已安装去使用")').click(timeout=3000)
                    break
                time.sleep(1)
            except:
                pass
        self.check_slide_code()
        self.page.query_selector('div:text-is("账号登录")').click()
        self.page.query_selector('#usernameId').fill(store['userName'])
        self.page.query_selector('#passwordId').fill(store['pwd'])
        time.sleep(1)
        self.page.query_selector('button:has-text("登录")').click()
        self.wait(self.page)
        # 检查是否可以登录
        can_login, error_text = self.can_login()
        if not can_login:
            return can_login, error_text
        # 检查是否有短信验证码
        self.check_sms_code(store['mobile'])
        is_success = False
        for i in range(20):
            try:
                if self.page.query_selector('div.user-name-id') is not None:
                    logger.info('登录成功...')
                    is_success = True
                    break
                time.sleep(1)
                logger.info(f'等待页面加载【{i+1}】秒...')
            except:
                pass
        for c in range(10):
            try:
                if self.page.query_selector('svg[data-testid="beast-core-icon-close"]:visible') is not None:
                    self.page.query_selector('svg[data-testid="beast-core-icon-close"]').click()
                    break
                time.sleep(1)
            except:
                pass
        for i in range(10):
            try:
                if self.page.query_selector('svg[data-testid="beast-core-modal-icon-close"]:visible') is not None:
                    self.page.query_selector('svg[data-testid="beast-core-modal-icon-close"]:visible').click()
                    break
                logger.info(f'检查是否有弹窗【{i+1}】秒...')
                time.sleep(1)
            except:
                pass
        for i in range(10):
            try:
                if self.page.query_selector('button:has-text("关闭"):visible') is not None:
                    self.page.query_selector('button:has-text("关闭"):visible').click()
                    break
                logger.info(f'检查是否有弹窗【{i+1}】秒...')
                time.sleep(1)
            except:
                pass
        self.page.query_selector('input.mms-header_search_new_box_input').click()
        time.sleep(1)
        self.page.query_selector('input.mms-header_search_new_box_input').click()
        self.page.query_selector('div.mms-header__open-item:has-text("客户端")').hover()
        time.sleep(1)
        if not is_success:
            raise Exception('登录失败')
        return True, ''

    def can_login(self):
        for c in range(5):
            try:
                if self.page.query_selector('span.info-error-text:visible') is not None:
                    error_text = self.page.query_selector('span.info-error-text:visible').text_content()
                    logger.info(error_text)
                    return False, error_text
                time.sleep(1)
            except:
                pass
        return True, ''

    # 获取图鉴账号密码
    def get_tujian_account(self):
        timestamp = int(time.time() * 1000)
        text = "mudi-key{}{}".format(timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/tjAccount/findOne?appId=mudi-key&sign={sign.upper()}&timestamp={timestamp}"
        res = requests.get(url)
        if res.status_code == 200:
            return res.json()['data']

    def check_slide_code(self):
        has_code = False
        for t in range(10):
            try:
                if self.page.query_selector('div[data-testid="beast-core-modal-body"]:visible') is not None:
                    has_code = True
                    break
                time.sleep(1)
            except:
                pass
        if has_code:
            logger.info("出现滑动验证码，开始滑动...")
            code_path = os.path.join(os.getcwd(), 'code.png')
            for k in range(20):
                try:
                    if self.page.query_selector('div[data-testid="beast-core-modal-body"]:visible') is None:
                        break
                    self.page.query_selector('div.slider-img').screenshot(path=code_path)
                    time.sleep(0.5)
                    dist = int(self.get_slider_xy(code_path))
                    box = self.page.query_selector('#slide-button').bounding_box()
                    track = self.get_tracks(dist+15, 1, self.ease_out_quart)
                    ix = int(box['x'] + box['width'] // 2)
                    iy = int(box['y'] + box['height'] // 2)
                    self.page.mouse.move(ix, iy)
                    self.page.mouse.down(button='left')
                    self.move_to_gap(self.page, ix, iy, track)
                    time.sleep(1.5)
                    logger.info("滑动完成...")
                    time.sleep(5)
                except:
                    self.page.query_selector('div.captcha-refresh:visible >> img').click(timeout=3000)
                    traceback.print_exc()

    def ease_out_quart(self, x):
        return 1 - pow(1 - x, 4)

    def get_tracks(self, distance, seconds, ease_func):
        distance += 0
        tracks = [0]
        offsets = [0]
        for t in numpy.arange(0.0, seconds, 0.1):
            ease = ease_func
            offset = round(ease(t / seconds) * distance)
            tracks.append(offset - offsets[-1])
            offsets.append(offset)
        tracks.extend([-3, -2, -3, -2, -2, -2, -2, -1, -0, -1, -1, -1])
        return tracks

    def move_to_gap(self, page, ix, iy, track):
        """
        慢速移动鼠标
        :param ix:
        :param iy:
        :param track:
        :return:
        """
        f_y = [10, 12, 4, 6, 8, -4, -6, -8]
        mx = ix
        while track:
            x = track.pop(0)
            mx = mx + x
            page.mouse.move(mx, iy + random.choice(f_y))
            time.sleep(0.1)
        time.sleep(1)
        page.mouse.up()

    def get_slider_xy(self, backImgPath):
        api = 'http://api.ttshitu.com/base64'
        with open(backImgPath, 'rb') as f:
            base64_data = base64.b64encode(f.read())
            b642 = base64_data.decode()
        params = {"typeid": "33", "image": b642, "username": self.tj_account['tjName'], "password": self.tj_account['tjPass']}
        headers = {'content-type': 'application/json;charset=UTF-8'}
        result = json.loads(requests.post(api, json=params, headers=headers).text)
        if result['success']:
            return result["data"]["result"]
        else:
            logger.info(result["message"])
            return result["data"]

    def check_sms_code(self, mobile):
        has_sms = False
        for t in range(10):
            try:
                if self.page.query_selector('input[placeholder="请输入短信验证码"]:visible') is not None:
                    has_sms = True
                    break
                time.sleep(1)
            except:
                pass
        if has_sms:
            logger.info('出现短信验证码')
            time.sleep(30)
            sms_text = self.get_sms_code(mobile)
            # 验证码格式示例：【拼多多】验证码：123456，您正在验证拼多多管理后台手机号，请于10分钟内完成验证，若非本人操作，请忽略此短信。
            if '拼多多' not in sms_text:
                logger.info('获取验证码失败')
                raise Exception('获取验证码失败')
            # 验证码示例：【有赞】您的验证码：123456，请勿泄露给其他人
            sms_code = sms_text.split('：')[1].split('，')[0]
            self.page.query_selector('input[placeholder="请输入短信验证码"]:visible').fill(sms_code)
            time.sleep(1)
            # 点击确认
            self.page.query_selector('button[data-tracking-click-viewid="account_login_confirmation"]').click()

    # 获取手机验证码
    def get_sms_code(self, mobile):
        for t in range(3):
            try:
                res = requests.get(f'http://1.95.166.150:8997/api/v1/sms/info/{mobile}')
                logger.info(f'获取手机验证码结果：{res.text}')
                sms_text = res.json()['data']
                if sms_text is not None and '拼多多' in sms_text:
                    return sms_text
                time.sleep(3)
            except:
                logger.info(traceback.format_exc())
        return ''

    def download_fund_flow(self, store, yesterday):
        logger.info('点击到【资金中心】...')
        new_page = None
        with self.page.expect_popup() as popup_info:
            self.page.query_selector('a:has-text("资金中心")').click(timeout=3000)
        new_page = popup_info.value
        self.wait(new_page)
        for i in range(20):
            try:
                if new_page.query_selector('a:text-is("收支明细")') is not None:
                    break
                time.sleep(1)
                logger.info(f'等待页面加载【{i+1}】秒...')
            except:
                pass
        self.get_balance(new_page, store['storeId'], yesterday)
        new_page.query_selector('a:text-is("收支明细")').click()
        self.wait(new_page)
        new_page.query_selector('input[placeholder="开始日期-结束日期"]').click()
        # 判断是否下载当月的资金流水
        now_month = datetime.datetime.now().strftime('%Y-%m')
        search_day = str(int(yesterday.split('-')[2]))
        if not yesterday.startswith(now_month):
            # 计算周期跟上个月差几个月
            last_month = (datetime.datetime.now().replace(day=1) - datetime.timedelta(days=1)).replace(day=1)
            first_day = datetime.datetime.strptime(yesterday, '%Y-%m-%d').replace(day=1)
            # 使用relativedelta计算差异
            delta = relativedelta(last_month, first_day)
            # 获取差异的月份数（这将是一个整数）
            months_diff = delta.years * 12 + delta.months
            # 选择月份
            if months_diff != 0:
                for t in range(months_diff):
                    new_page.query_selector('section[data-testid="beast-core-monthRangePicker-year-header"] >> i[data-testid="beast-core-icon-left"]').click(timeout=3000)
                    time.sleep(1)
            td_list = new_page.query_selector_all('table[data-testid="beast-core-rangePicker-table"] >> nth=0 >> td')
            for td in td_list:
                class_name = td.get_attribute('class')
                day = td.text_content().strip()
                if 'outOfMonth' not in class_name and day == search_day:
                    td.click()
                    td.click()
                    break
        else:
            # 下载当月的账单
            td_list = new_page.query_selector_all('table[data-testid="beast-core-rangePicker-table"] >> nth=1 >> td')
            for td in td_list:
                class_name = td.get_attribute('class')
                day = td.text_content().strip()
                if 'outOfMonth' not in class_name and day == search_day:
                    td.click()
                    td.click()
                    break
        new_page.query_selector('div[data-testid="beast-core-portal-main"] >> button:has-text("确认")').click()
        time.sleep(1)
        search_time = new_page.query_selector('input[placeholder="开始日期-结束日期"]').get_attribute('value')
        if search_time != f'{yesterday} 00:00:00 ~ {yesterday} 23:59:59':
            raise Exception(f'查询时间错误：应该查询【{yesterday} 00:00:00 ~ {yesterday} 23:59:59】，实际查询【{search_time}】')
        with new_page.expect_response('https://cashier.pinduoduo.com/templar/api/bill/pagingQueryMallBalanceBillListForMms?*') as res:
            new_page.query_selector('button:has-text("查询")').click()
        response = res.value
        if response.status == 200:
            if response.json()['result']['total'] == 0:
                logger.info('暂无数据')
                new_page.close()
                return None
        else:
            logger.info('查询失败')
            raise Exception('查询失败')
        logger.info(f"共【{response.json()['result']['total']}】条数据")
        logger.info('点击【导出】...')
        with new_page.expect_popup() as popup_info:
            new_page.query_selector('#exportBalance-btn').click()
        download_page = popup_info.value
        for i in range(20):
            try:
                if download_page.query_selector('div.export-history-bills-card') is not None:
                    break
                time.sleep(1)
                logger.info(f'等待页面加载【{i + 1}】秒...')
            except:
                pass
        card_list = download_page.query_selector_all('div.export-history-bills-card')
        # 入账时间：昨天 00:00:00 至昨天 23:59:59
        bill_time = f'{yesterday} 00:00:00 至{yesterday} 23:59:59'
        timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        file_path = os.path.join(self.fund_flow_download_path, f'pddFundFlow-{store["platformStoreName"]}-{yesterday.replace("-", "")}-{timestamp}.zip')
        for card in card_list:
            bill_time_text = card.query_selector('div.export-history-bills-card-header-detail-content >> div:has(span:has-text("入账时间"))').text_content()
            if bill_time in bill_time_text:
                logger.info(f'找到入账时间【{bill_time}】的下载记录...')
                status = card.query_selector('button:has-text("下载账单")').text_content().strip()
                logger.info(f'状态：{status}')
                if '下载账单' == status:
                    with download_page.expect_download() as download_info:
                        card.query_selector('button:has-text("下载账单")').click()
                    download_obj = download_info.value
                    # 删除旧文件
                    if os.path.exists(file_path):
                        os.remove(file_path)
                    download_obj.save_as(file_path)
                    # 等待文件下载完成
                    for i in range(60):
                        if os.path.exists(file_path):
                            break
                        time.sleep(1)
                break
        if not os.path.exists(file_path):
            logger.info(traceback.format_exc())
            raise Exception(f"【{file_path}】下载失败")
        logger.info(f"【{file_path}】下载成功")
        unzip_path = os.path.join(self.fund_flow_download_path, yesterday)
        fund_flow_file = self.get_unzip_file(file_path, unzip_path)
        download_page.close()
        new_page.close()
        return fund_flow_file

    def get_fund_flow_count(self, period):
        logger.info('点击到【资金中心】...')
        new_page = None
        for i in range(10):
            try:
                with self.page.expect_popup() as popup_info:
                    self.page.query_selector('a:has-text("资金中心")').click(timeout=3000)
                new_page = popup_info.value
                break
            except:
                pass
        self.wait(new_page)
        for i in range(20):
            try:
                if new_page.query_selector('a:text-is("收支明细")') is not None:
                    break
                time.sleep(1)
                logger.info(f'等待页面加载【{i+1}】秒...')
            except:
                pass
        new_page.query_selector('a:text-is("收支明细")').click()
        self.wait(new_page)
        logger.info('点击月汇总')
        new_page.query_selector('#monthly-detail').click()
        time.sleep(2)
        # 选择年份
        new_page.query_selector('div.search-form-box >> input').click(timeout=3000)
        year = period.split('-')[0]
        time.sleep(1)
        new_page.query_selector(f'ul[role="listbox"]:visible >> li:has-text("{year}")').click()
        with new_page.expect_response('https://cashier.pinduoduo.com/templar/api/bill/queryMallBalanceMonthlySummary?*') as res:
            new_page.query_selector('button:has-text("查询")').click()
        response = res.value
        if response.status == 200:
            filter_list = list(filter(lambda x: x['time'] == period, response.json()['result']['summaryList']))
            if len(filter_list) > 0:
                return int(filter_list[0]['incomeNumber']) + int(filter_list[0]['outcomeNumber'])
            else:
                return 0
        else:
            logger.info('查询失败')
            raise Exception('查询失败')

    # 获取余额
    def get_balance(self, page, store_id, search_date):
        try:
            balance_amount = page.query_selector('#available-amount').text_content()
            # 保存余额
            self.update_balance(store_id, balance_amount, search_date)
        except:
            logger.info(traceback.format_exc())

    def update_balance(self, store_id, balance_amount, search_date):
        data = {'storeId': store_id, 'balanceAmount': balance_amount, 'billDate': search_date}
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/balance/updateBalance?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
        logger.info(f'url：{url}')
        logger.info(f'保存参数：{data}')
        res = requests.post(url, json=data)
        logger.info(f'保存结果：{res.text}')
        if res.status_code == 200:
            return res.json()['data']

    def download_deposit(self, store, yesterday):
        for i in range(10):
            try:
                if self.page.query_selector('svg[data-testid="beast-core-modal-icon-close"]:visible') is not None:
                    self.page.query_selector('svg[data-testid="beast-core-modal-icon-close"]:visible').click()
                    break
                logger.info(f'检查是否有弹窗【{i+1}】秒...')
                time.sleep(1)
            except:
                pass
        logger.info('点击到【资金中心】...')
        with self.page.expect_popup() as popup_info:
            self.page.query_selector('a:has-text("保证金")').click(timeout=3000)
        new_page = popup_info.value
        self.wait(new_page)
        for i in range(20):
            try:
                if new_page.query_selector('div.deposit-index-cards-container-header-title >> a:has-text("账单明细")') is not None:
                    break
                time.sleep(1)
                logger.info(f'等待页面加载【{i+1}】秒...')
            except:
                pass
        logger.info('点击【账单明细】')
        with new_page.expect_popup() as popup_info:
            new_page.query_selector('div.deposit-index-cards-container-header-title >> a:has-text("账单明细")').click()
        deposit_page = popup_info.value
        for i in range(10):
            try:
                if deposit_page.query_selector('input[placeholder="请选择时间范围"]') is not None:
                    break
                logger.info(f'等待页面加载【{i+1}】秒...')
                time.sleep(1)
            except:
                pass
        logger.info('选择【日期】，点击昨天...')
        deposit_page.query_selector('input[placeholder="请选择时间范围"]').click()
        time.sleep(0.5)
        # 判断是否下载当月的保证金明细
        now_month = datetime.datetime.now().strftime('%Y-%m')
        search_day = str(int(yesterday.split('-')[2]))
        if not yesterday.startswith(now_month):
            # 计算周期跟上个月差几个月
            last_month = (datetime.datetime.now().replace(day=1) - datetime.timedelta(days=1)).replace(day=1)
            first_day = datetime.datetime.strptime(yesterday, '%Y-%m-%d').replace(day=1)
            # 使用relativedelta计算差异
            delta = relativedelta(last_month, first_day)
            # 获取差异的月份数（这将是一个整数）
            months_diff = delta.years * 12 + delta.months
            # 选择月份
            if months_diff != 0:
                for t in range(months_diff):
                    deposit_page.query_selector('section[data-testid="beast-core-monthRangePicker-year-header"] >> i[data-testid="beast-core-icon-left"]').click(timeout=3000)
                    time.sleep(1)
            td_list = deposit_page.query_selector_all('table[data-testid="beast-core-rangePicker-table"] >> nth=0 >> td')
            for td in td_list:
                class_name = td.get_attribute('class')
                day = td.text_content().strip()
                if 'outOfMonth' not in class_name and day == search_day:
                    td.click()
                    td.click()
                    break
        else:
            # 下载当月的账单
            td_list = deposit_page.query_selector_all('table[data-testid="beast-core-rangePicker-table"] >> nth=1 >> td')
            for td in td_list:
                class_name = td.get_attribute('class')
                day = td.text_content().strip()
                if 'outOfMonth' not in class_name and day == search_day:
                    td.click()
                    td.click()
                    break
        deposit_page.query_selector('div[data-testid="beast-core-portal-main"] >> button:has-text("确认")').click()
        search_time = deposit_page.query_selector('input[placeholder="请选择时间范围"]').get_attribute('value')
        if search_time != f'{yesterday} 00:00:00 ~ {yesterday} 23:59:59':
            deposit_page.close()
            raise Exception(f'查询时间错误：应该查询【{yesterday} 00:00:00 ~ {yesterday} 23:59:59】，实际查询【{search_time}】')
        logger.info('点击【查询】...')
        with deposit_page.expect_response('https://cashier.pinduoduo.com/templar/api/depositBill/queryMerchantDepositBillList?*') as res:
            deposit_page.query_selector('#search-btn').click()
        response = res.value
        total = 0
        if response.status == 200:
            total = response.json()['result']['total']
            logger.info(f'共【{total}】条数据')
        else:
            logger.info('查询失败')
        if total > 0:
            logger.info('点击【导出】')
            with deposit_page.expect_popup() as popup_info:
                deposit_page.query_selector('#export-btn').click()
            export_page = popup_info.value
            for i in range(10):
                try:
                    if self.page.query_selector('div.export-history-bills-card') is not None:
                        break
                    logger.info(f'等待页面加载【{i + 1}】秒...')
                    time.sleep(1)
                except:
                    pass
            # 入账时间：昨天 00:00:00 至昨天 23:59:59
            bill_time = f'{yesterday} 00:00:00 至{yesterday} 23:59:59'
            timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
            file_path = os.path.join(self.deposit_download_path, f'pddDeposit-{store["platformStoreName"]}-{yesterday.replace("-", "")}-{timestamp}.zip')
            card_list = export_page.query_selector_all('div.export-history-bills-card')
            for card in card_list:
                bill_time_text = card.query_selector('div.export-history-bills-card-header-detail-content >> div:has(span:has-text("入账时间"))').text_content()
                if bill_time in bill_time_text:
                    logger.info(f'找到入账时间【{bill_time}】的下载记录...')
                    status = card.query_selector('button:has-text("下载账单")').text_content().strip()
                    logger.info(f'状态：{status}')
                    if '下载账单' == status:
                        with export_page.expect_download() as download_info:
                            card.query_selector('button:has-text("下载账单")').click()
                        download_obj = download_info.value
                        # 删除旧文件
                        if os.path.exists(file_path):
                            os.remove(file_path)
                        download_obj.save_as(file_path)
                        # 等待文件下载完成
                        for i in range(60):
                            if os.path.exists(file_path):
                                break
                            time.sleep(1)
                    break
            if not os.path.exists(file_path):
                raise Exception(f"【{file_path}】下载失败")
            logger.info(f"【{file_path}】下载成功")
            unzip_path = os.path.join(self.deposit_download_path, yesterday)
            deposit_file = self.get_unzip_file(file_path, unzip_path)
            deposit_page.close()
            return deposit_file
        deposit_page.close()
        return None

    def get_deposit_count(self, period):
        for i in range(10):
            try:
                if self.page.query_selector('svg[data-testid="beast-core-modal-icon-close"]:visible') is not None:
                    self.page.query_selector('svg[data-testid="beast-core-modal-icon-close"]:visible').click()
                    break
                logger.info(f'检查是否有弹窗【{i+1}】秒...')
                time.sleep(1)
            except:
                pass
        logger.info('点击到【资金中心】...')
        with self.page.expect_popup() as popup_info:
            self.page.query_selector('a:has-text("保证金")').click(timeout=3000)
        new_page = popup_info.value
        self.wait(new_page)
        for i in range(20):
            try:
                if new_page.query_selector('div.deposit-index-cards-container-header-title >> a:has-text("账单明细")') is not None:
                    break
                time.sleep(1)
                logger.info(f'等待页面加载【{i+1}】秒...')
            except:
                pass
        logger.info('点击【账单明细】')
        with new_page.expect_popup() as popup_info:
            new_page.query_selector('div.deposit-index-cards-container-header-title >> a:has-text("账单明细")').click()
        deposit_page = popup_info.value
        for i in range(10):
            try:
                if deposit_page.query_selector('input[placeholder="请选择时间范围"]') is not None:
                    break
                logger.info(f'等待页面加载【{i+1}】秒...')
                time.sleep(1)
            except:
                pass
        deposit_page.query_selector('input[placeholder="请选择时间范围"]').click()
        time.sleep(1)
        # 计算周期跟上个月差几个月
        last_month = (datetime.datetime.now().replace(day=1) - datetime.timedelta(days=1)).replace(day=1)
        search_month = datetime.datetime.strptime(period+'-01', '%Y-%m-%d')
        # 使用relativedelta计算差异
        delta = relativedelta(last_month, search_month)
        # 获取差异的月份数（这将是一个整数）
        months_diff = delta.years * 12 + delta.months
        # 选择月份
        if months_diff != 0:
            for t in range(months_diff):
                deposit_page.query_selector('section[data-testid="beast-core-monthRangePicker-year-header"] >> i[data-testid="beast-core-icon-left"]').click(timeout=3000)
                time.sleep(1)
        td_list = deposit_page.query_selector_all('table[data-testid="beast-core-rangePicker-table"] >> nth=0 >> td')
        is_first_td = True
        last_td = None
        for td in td_list:
            class_name = td.get_attribute('class')
            if 'outOfMonth' not in class_name and is_first_td:
                td.click(timeout=3000)
                is_first_td = False
            # 在当前月的范围内
            if 'outOfMonth' not in class_name:
                last_td = td
            if 'outOfMonth' in class_name and last_td is not None:
                last_td.click(timeout=3000)
                break
        deposit_page.query_selector('div[data-testid="beast-core-rangePicker-dropdown-contentRoot"] >> button:has-text("确认")').click(timeout=3000)
        time.sleep(1)
        with deposit_page.expect_response('https://cashier.pinduoduo.com/templar/api/depositBill/queryMerchantDepositBillList?*') as res:
            deposit_page.query_selector('#search-btn').click()
        response = res.value
        if response.status == 200:
            return response.json()['result']['total']
        else:
            logger.info('查询失败')


    def get_all_files(self, path, file_list):
        if not os.path.exists(path):
            return
        for file in os.listdir(path):
            if os.path.isfile(os.path.join(path, file)):
                file_list.append(os.path.join(path, file))
            else:
                self.get_all_files(os.path.join(path, file), file_list)

    def get_unzip_file(self, file_path, path):
        # 删除旧文件
        file_list = []
        self.get_all_files(path, file_list)
        for file in file_list:
            os.remove(file)
        # 解压文件
        self.unzip(file_path, path)
        for file in os.listdir(path):
            return os.path.join(path, file)
        return None

    def unzip(self, zip_path, extract_path):
        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            zip_ref.extractall(extract_path)

    def get_store_account(self, platform, type):
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/storeAccount/getAccountList/{platform}?appId={self.app_id}&type={type}&sign={sign.upper()}&timestamp={timestamp}"
        res = requests.get(url)
        if res.status_code == 200:
            return res.json()['data']

    def upload_file(self, uri, coding_param, file_list):
        try:
            timestamp = int(time.time() * 1000)
            text = "{}{}{}".format(self.app_id, timestamp, self.secret)
            sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
            logger.info("正在上传文件到服务器")
            url = self.host + uri + f"?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
            files = []
            for file in file_list:
                files.append(('file', (open(file, 'rb'))))
            logger.info(f'上传文件到服务器url：{url}')
            response = requests.request("POST", url, files=files, headers={'codingParam': coding_param}, timeout=180)
            logger.info('上传文件到服务器结果：' + response.text)
        except:
            logger.info(traceback.format_exc())

    # 更新流程日志状态
    def save_log_record(self, data):
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/logRecord/saveLog?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
        logger.info(f'保存日志参数：{data}')
        res = requests.post(url, json=data)
        logger.info(f'保存日志结果：{res.text}')
        if res.status_code == 200:
            return res.json()['data']

    # 获取任务ID
    def get_job_id(self, key):
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/storeAccount/getJobId/{key}?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
        res = requests.get(url)
        logger.info(res.text)
        if res.status_code == 200:
            return res.json()['data']

    def encode_param(self, data_list):
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/storeAccount/codingParams?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
        res = requests.post(url, data=json.dumps(data_list), headers={'content-type': 'application/json'})
        if res.status_code == 200:
            return res.json()['data']

    def wait(self, page, seconds=1):
        try:
            page.wait_for_load_state(state="domcontentloaded")
            time.sleep(seconds)
        except:
            pass

    def close(self):
        try:
            if self.page:
                self.page.close()
        except:
            pass
        try:
            if self.browser:
                self.browser.close()
        except:
            pass
        try:
            if self.context:
                self.context.close()
        except:
            pass

    # 更新日志
    def update_log(self, log_id_list, message):
        data = {'logIdList': log_id_list, 'message': message}
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/logRecord/updateLog?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
        logger.info(f'url：{url}')
        logger.info(f'保存参数：{data}')
        res = requests.post(url, json=data)
        logger.info(f'保存结果：{res.text}')
        if res.status_code == 200:
            return res.json()['data']